#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>

#include "imdraw.h"
#include "../image.h"

#define adjust( a, min, max ) a = ((a) < min) ? min : ((a)>=max) ? (max-1) : (a);

#define swap( a, b ) { int tmp; tmp = (a); (a) = (b); (b) = tmp; }
#define round( val ) ( ( (val)-(int)(val) ) ) > 0.5 ? (int)val+1 : (int)val
#define abs( val ) (val)<0?-(val):(val)


static Color __fg_color;
static Color __bg_color;
static Font __font_;

static void _draw_print_text(Image * img, int row, int col, char fill_ground, char * image_label);

/* Color ==================================================================== */
Color image_draw_color_new(int color) {
	Color cor;
	cor.px = color;
	return cor;
}

void image_draw_set_color(Color cor) {
	__fg_color = cor;
}

void image_draw_set_fg_color(Color cor) {
	__fg_color = cor;
}

void image_draw_set_bg_color(Color cor) {
	__bg_color = cor;
}

/* Primitives =============================================================== */
inline void image_draw_put_pixel(Image * img, int x, int y) {
	if (x < 0 || x >= img->width) return;
	if (y < 0 || y >= img->height) return;

	img->methods.set_pixel(img, x, y, __fg_color.px);
}

void image_draw_line(Image * img, int x0, int y0, int x1, int y1) {

	//if (x1 > x0) swap(x1, x0);
	//if (y1 > y0) swap(y1, y0);
	//adjust(x0, 0, img->width);
	//adjust(x1, 0, img->width);
	//adjust(y0, 0, img->height);
	//adjust(y1, 0, img->height);

	int dx = abs(x1 - x0);
	int dy = -abs(y1 - y0);

	int sx = x0 < x1 ? 1 : -1;
	int sy = y0 < y1 ? 1 : -1;

	int err = dx + dy;
	int e2; /* error value e_xy */

	for (;;) { /* loop */

		image_draw_put_pixel(img, x0, y0);
		//im_set_pixel_gray(gray, width, height, x0, y0);
		if (x0 == x1 && y0 == y1) break;
		e2 = 2 * err;
		if (e2 >= dy) {
			err += dy;
			x0 += sx;
		} /* e_xy+e_x > 0 */
		if (e2 <= dx) {
			err += dx;
			y0 += sy;
		} /* e_xy+e_y < 0 */
	}

}

void image_draw_square(Image * img, int x, int y, int ray) {
	int x1, x2, y1, y2;

	x1 = x - ray;
	x2 = x + ray;
	y1 = y - ray;
	y2 = y + ray;
	/*
		if (x1 < 0)
			x1 = 0;
		if (x2 >= img->width)
			x2 = img->width - 1;
		if (y1 < 0)
			y1 = 0;
		if (y2 >= img->height)
			y2 = img->height - 1;
	 */

	image_draw_line(img, x1, y1, x2, y1);
	image_draw_line(img, x1, y1, x1, y2);
	image_draw_line(img, x2, y2, x2, y1);
	image_draw_line(img, x2, y2, x1, y2);
}

void image_draw_cross(Image * img, int x, int y, int ray) {
	image_draw_line(img, x - ray, y, x + ray, y);
	image_draw_line(img, x, y - ray, x, y + ray);

}

void image_draw_rect(Image * img, int x0, int y0, int x1, int y1) {
	/* horizontal */
	image_draw_line(img, x0, y0, x1, y0);
	image_draw_line(img, x0, y1, x1, y1);
	/* vertical */
	image_draw_line(img, x0, y0, x0, y1);
	image_draw_line(img, x1, y0, x1, y1);
}

void image_draw_circle(Image * img, int xm, int ym, int ray) {
	int x = -ray, y = 0, err = 2 - 2 * ray; /* II. Quadrant */
	do {
		//img->methods.set_pixel( img, );
		image_draw_put_pixel(img, xm - x, ym + y); /*   I. Quadrant */
		image_draw_put_pixel(img, xm - y, ym - x); /*  II. Quadrant */
		image_draw_put_pixel(img, xm + x, ym - y); /* III. Quadrant */
		image_draw_put_pixel(img, xm + y, ym + x); /*  IV. Quadrant */

		//im_set_pixel_gray(gray, width, height, xm - x, ym + y); /*   I. Quadrant */
		//im_set_pixel_gray(gray, width, height, xm - y, ym - x); /*  II. Quadrant */
		//im_set_pixel_gray(gray, width, height, xm + x, ym - y); /* III. Quadrant */
		//im_set_pixel_gray(gray, width, height, xm + y, ym + x); /*  IV. Quadrant */

		ray = err;
		if (ray > x) err += ++x * 2 + 1; /* e_xy+e_x > 0 */
		if (ray <= y) err += ++y * 2 + 1; /* e_xy+e_y < 0 */
	} while (x < 0);
}

void image_draw_ellipse(Image * img, int xc, int yc, int a, int b, double ang) {
	float t;
	float inc;
	int x0, x1;
	int y0, y1;

	double cosrad, sinrad;
	double cost, sint;

	ang = -(ang * M_PI) / 180;

	inc = 0.01;
	t = 0.0;
	cosrad = cos(ang);
	sinrad = sin(ang);

	cost = cos(t);
	sint = sin(t);

	x0 = xc + a * cost * cosrad - b * sint * sinrad;
	y0 = yc + a * cost * sinrad + b * sint * cosrad;

	t += inc;

	do {
		cost = cos(t);
		sint = sin(t);

		x1 = xc + a * cost * cosrad - b * sint * sinrad;
		y1 = yc + a * cost * sinrad + b * sint * cosrad;

		x0 = x1;
		y0 = y1;
		t += inc;

		if (x1 < 0 || x1 >= img->width) continue;
		if (y1 < 0 || y1 >= img->height) continue;
		image_draw_line(img, x0, y0, x1, y1);

	} while (t <= (M_PI + M_PI));

}

/* Fonts ==================================================================== */
void image_draw_set_font(Font f) {
	__font_ = f;
}

static void _draw_print_text(Image * img, int col, int row, char fill_ground, char * image_label) {

	int i, x, y, f, len;
	int idx;
	int w, h;

	int width;
	int height;
	unsigned char * image;

	__font_ = FONT_6x11;

	width = img->width;
	height = img->height;
	image = img->data;

	len = strlen(image_label);


	for (y = 0; y < __font_.char_height; y++) {
		h = row + y;
		if (h >= height || h < 0) continue;

		for (x = 0; x < len; x++) {

			f = __font_.fontdata[image_label[x] * __font_.char_height + y];

			for (i = 0; i < __font_.char_width; i++) {

				w = col + (__font_.char_width * x) + i;

				if (w >= width || w < 0) continue;

				if (f & (__font_.mask >> i)) {

					image_draw_put_pixel(img, w, h);
					/*
						idx = (h * width + w)*3;
						image[idx] = __fg_color.rgb.r;
						image[idx + 1] = __fg_color.rgb.g;
						image[idx + 2] = __fg_color.rgb.b;
					 */

				} else {
					if (fill_ground) {

						image_draw_put_pixel(img, w, h);
						idx = (h * width + w)*3;
						image[idx] = __bg_color.rgb.r;
						image[idx + 1] = __bg_color.rgb.g;
						image[idx + 2] = __bg_color.rgb.b;
					}

				}
			}

		}
	}
}

void image_draw_print_text(Image * img, int x, int y, int fillbg, char * template, ...) {

	char msg[256];
	va_list ap;

	va_start(ap, template);
	vsprintf(msg, template, ap);
	va_end(ap);

	_draw_print_text(img, x, y, fillbg, msg );
}
